/**
 * Copyright (c) suzuki ryoutoku
 * See this code regarding the Apache License Version 2.0
 * @file StripCreator.h
 * @author suzuki ryoutoku
 */

//=============================================================================
//	Protected include multiple file
//=============================================================================
#ifndef STRIPCREATOR_H
#define STRIPCREATOR_H

//=============================================================================
//	Preprocessor
//=============================================================================
#include "include/declare.h"
#include "Graphics.h"

//=============================================================================
//	Declare class
//=============================================================================
/**
 * @author suzuki ryoutoku
 * @date 2007-10-30
 * @version 1.0
 */
namespace strip
{
  class Triangle;
  class Edge;
  class Vertex;
}

//=============================================================================
//	define class
//=============================================================================
/**
 * Face's edge
 * @author suzuki ryoutoku
 * @date 2007-10-29
 * @version 1.0
 */
class strip::Edge
{
  // closed member
private:
  int					 _first;//!< index of first order
  int					_second;//!< index of second order
  strip::Triangle*	 _ascending;//!< m_first -> m_second
  strip::Triangle*	_descending;//!< m_second -> m_first

  // opened method
public:
  Edge();
  ~Edge();

  strip::Triangle* getNeighbourTriangle(strip::Triangle* face);

  // friend class
public:
  friend class strip::Triangle;
  friend class library::graphics::StripCreator;
};


/**
 * Triangle for creating strip
 * @author suzuki ryoutoku
 * @date 2007-10-29
 * @version 1.0
 */
class strip::Triangle
{
public:
  int		   _face_index;
  int			 _index[3];
  strip::Edge* 	 _edges[3];
  bool		 _edge_path[3];//!< when it's true, ascending order
  int		   	   _degree;
  int			    _state;//!< This value is substituted from enum State.

public:
  Triangle(int arg1, int arg2, int arg3);
  ~Triangle();
  strip::Edge* findViaEdgeWithCurrentBufferA(strip::Edge* iedge);
  strip::Edge* findViaEdgeWithCurrentBufferB(strip::Edge* iedge);
  int getThitherVertex(strip::Edge* arg);
  int getAcrossVertex(strip::Triangle* tri);
  void printAttrubite(void);
  void notifyLeaving(void);
public:
  friend class library::graphics::StripCreator;
  friend class strip::Vertex;

public:
  enum State{
	NORMAL_EDGE_1	= 0x001,
	NORMAL_EDGE_2	= 0x002,
	NORMAL_EDGE_3	= 0x004,
	REVERSE_EDGE_1	= 0x010,
	REVERSE_EDGE_2	= 0x020,
	REVERSE_EDGE_3	= 0x040,
	USED			= 0x100,
  };
};

/**
 * This class express a vertex of triangle connectivity.
 * The vertex has information of associated triangles.
 * @author r-suzuki
 * @date 2009-1-12
 * @version 1.0
 */
class strip::Vertex
{
private:
  int 				_index;
  vector<int>	_tri_index;

public:
  ~Vertex();

  bool operator < (const strip::Vertex& arg) const
  {
	if( _tri_index.size() > arg._tri_index.size() ) return true;
	return false;
  }
  int getStartTriangle(vector<strip::Triangle>*	_triangles);

public:
  friend class library::graphics::StripCreator;
};

/**
 * This class has option and argument of creating triangle strip.
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-7-3 New created
 */
class library::graphics::StripCreatingOption
{
private:
  PolygonBody*			 _body;//!< This value has targeted clusteres.
  SelectStarting _start_option;//!< This value is selecting way to decide start.

  // opened method
public:
  StripCreatingOption(PolygonBody* body,
					  SelectStarting start_option = IO_ORDER);

  // friend class
public:
  friend class library::graphics::StripCreator;
};


/**
 * Creator of strip
 * @author suzuki ryoutoku
 * @date 2007-10-30
 * @version 1.0
 */
class library::graphics::StripCreator
{
private:
  vector<strip::Edge>			_edges;
  vector<strip::Triangle>	_triangles;
  vector<strip::Vertex>		 _vertcies;
  library::log::LogManager*    _logger;

public:
  StripCreator(library::log::LogManager* arg);
  ~StripCreator();
  int  createTriangleStrip(StripCreatingOption* sco);
  
private:
  int createEdges(int vertex_sum);
  int createTriangles(Cluster* cluster);
  int createVertcies(PolygonBody* body);
  strip::Triangle* getStartTriangle(library::graphics::StripCreatingOption*);
  bool extendNormal(vector<strip::Triangle*> &striplist,
					strip::Triangle* start, 
					strip::Edge* edge,
					int edge_no);
  bool extendReverse(vector<strip::Triangle*> &striplist,
					 strip::Triangle* start, 
					 strip::Edge* edge,
					 int edge_no);
  void refreshTriangleState(void);
  bool constructTriangleStripData(int* data, 
								  vector<strip::Triangle*> &striplist,
								  strip::Triangle* start,
								  vector<strip::Triangle*> &reverse);

  void setDegree(void);

  void display_edges(void);
  
};



//=============================================================================
//	Include gard
//=============================================================================
#endif
